package com.novax.ex.ai.factory;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.novax.ex.ai.request.davinci.DavinciRequest;
import com.novax.ex.ai.response.davinci.Choice;
import com.novax.ex.ai.response.davinci.DavinciResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.rmi.RemoteException;
import java.util.Optional;

/**
 * openAI的达芬奇模型
 */
@Slf4j
@Service
public class DavinciAdapter implements OpenAIApi {

    // 从配置中心拉取数据，拉取不到使用默认值
    @Value("${openai.chatgpt.apiurl:https://api.openai.com/v1/engines/text-davinci-003/completions}")
    private String apiUrl;

    @Value("${openai.chatgpt.apiKey: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}")
    private String apiKey;

    @Override
    public String invokeApi(String prompt) throws RemoteException {

        // 构建Davinci model的请求体
        DavinciRequest requestBody = new DavinciRequest();
        requestBody.setPrompt(prompt);
        requestBody.setMax_tokens(1000);

        HttpResponse response = HttpRequest.post(apiUrl)
                .header("Content-Type", "application/json")
                .header("Authorization", "Bearer " + apiKey)
                .setHttpProxy("127.0.0.1", 7890)
                .body(JSON.toJSONString(requestBody))
                .execute();

        // 如果调用不OK，这里手动抛出来异常，然后AOP捕捉到这个异常后进行重试
        if (!response.isOk()) throw new RemoteException("远程调用OpenAI服务报错。。。");

        // 这里使用Optional将response中的数据解析并将我们想要的信息返回
        String text = Optional.of(response)
                .map(resp -> JSON.parseObject(response.body(), DavinciResponse.class))
                .map(DavinciResponse::getChoices)
                .map(CollectionUtil::getFirst)
                .map(Choice::getText).orElse("");

        // 如果在Optional处理的过程中发生了空指针异常
        if (StrUtil.isBlank(text)) {
            log.info("Davinci模型，在问题为：[{}]的时候，解析返回的结果报错", response.body());
            throw new RuntimeException("解析OpenAI返回的结果报错。。。");
        }

        return text;
    }

    @Override
    public boolean checkHealth() {

        RequestBody requestBody = new RequestBody();
        requestBody.setPrompt("hi");
        requestBody.setMax_tokens(10);

        HttpResponse response = HttpRequest.post(apiUrl)
                .header("Content-Type", "application/json")
                .header("Authorization", "Bearer " + apiKey)
                .setHttpProxy("127.0.0.1", 7890)
                .body(JSON.toJSONString(requestBody))
                .execute();

        // 调用成功返回结果
        return response.isOk();
    }


    @Data
    private static class RequestBody {
        // 发送给GPT的问题
        private String prompt;
        // 限制返回的最大字数
        private Integer max_tokens;
    }

}
